package org.springframework.boot.netty.argumentResolver;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.util.ReferenceCountUtil;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.netty.listener.Message;
import org.springframework.boot.netty.support.ModelAndView;
import org.springframework.boot.netty.view.View;
import org.springframework.boot.netty.viewResolver.ViewResolverComposite;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.Method;
import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

/**
 * Author: huoxingzhi
 * Date: 2020/12/22
 * Email: hxz_798561819@163.com
 */
public class ModelAndViewReturnValueArgumentResolver extends ReturnValueArgumentResolverAdapter implements SmartInitializingSingleton{

    private ViewResolverComposite viewResolverComposite;

    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        Method method = methodParameter.getMethod();
        Class<?> returnType = method.getReturnType();
        return ModelAndView.class.isAssignableFrom(returnType);
    }

    @Override
    public void resolveArgument(Message message, Object returnValue, MethodParameter methodParameter) throws Exception {
        Channel currentChannel = message.getCurrentChannel();
        ReferenceCountUtil.release(message.getContent());
        View view = viewResolverComposite.resolveViewName((ModelAndView) returnValue);
        if(null!=view){
            view.render(currentChannel, (ModelAndView) returnValue);
        }else {
            DefaultFullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND, buildDefaultForbiddenByteBuf());
            currentChannel.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        }

    }


    private ByteBuf buildDefaultForbiddenByteBuf(){
        String response = "<!DOCTYPE html>\n" +
                "<html>\n" +
                "<head>\n" +
                "    <title>You can't do that (404)</title>\n" +
                "    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n" +
                "    <style type=\"text/css\">\n" +
                "        body { background-color: #fff; color: #666; text-align: center; font-weight:bold ; font-family: Arial, \"Times New Roman\", \"楷体\" ; }\n" +
                "        div.dialog {\n" +
                "            width: 25em;\n" +
                "            padding: 0 4em;\n" +
                "            margin: 4em auto 0 auto;\n" +
                "            border: 1px solid #ccc;\n" +
                "            border-right-color: #999;\n" +
                "            border-bottom-color: #999;\n" +
                "        }\n" +
                "        h1 { font-size: 400%; color: #f00; line-height: 1em; }\n" +
                "    </style>\n" +
                "</head>\n" +
                "\n" +
                "<body>\n" +
                "<div class=\"dialog\">\n" +
                "    <h1>404</h1>\n" +
                "    <p>That Resource Not Found!</p>\n" +
                "</div>\n" +
                "</body>\n" +
                "</html>";
        byte[] bytes = response.getBytes();
        return ByteBufAllocator.DEFAULT.buffer(bytes.length).writeBytes(bytes);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        super.setApplicationContext(applicationContext);
    }

    @Override
    public void afterSingletonsInstantiated() {
        this.viewResolverComposite = new ViewResolverComposite();
        viewResolverComposite.setApplicationContext(this.applicationContext);
    }
}
